\section{python入门基础}

\subsection{字典的使用}
\begin{questionbox}
掌握字典（Dictionary）的高级用法，包括嵌套数据结构，并结合函数进行模块化操作。这是数据管理和抽象的基础。创建一个命令行电话簿应用。用户可以添加联系人及其电话号码，查询、更新和删除联系人信息。
\end{questionbox}

为了解决这个问题我们可以创建一个字典。字典的键是联系人姓名，值是另一个字典，包括电话号码、邮箱等信息。而主体则使用一个死循环，直到用户选择退出。代码实现了五个功能：
我们实现了以下五个函数来管理电话簿：
\begin{itemize}
    \item \texttt{add\_contact(phone\_book)}: 提示用户输入姓名和电话，然后将其添加到主字典中。
    \item \texttt{find\_contact(phone\_book)}: 提示用户输入姓名，然后在字典中查找并显示其信息。如果不存在，则提示用户。
    \item \texttt{update\_contact(phone\_book)}: 提示用户输入要更新的联系人姓名，如果存在，则允许用户输入新的电话号码。
    \item \texttt{delete\_contact(phone\_book)}: 提示用户输入要删除的联系人姓名，并从字典中移除。
    \item \texttt{display\_all(phone\_book)}: 遍历字典，打印所有联系人的信息，以无序列表的形式输出，便于在 LaTeX 文档中展示。
\end{itemize}

代码部分如下：
\begin{lstlisting}
phone_book = {}

def add_contact():
    name = input("请输入联系人姓名: ")
    phone = input("请输入电话号码: ")
    phone_book[name] = phone
    print(f"联系人 {name} 添加成功。")

def find_contact():
    name = input("请输入要查询的姓名: ")
    if name in phone_book:
        print(f"{name} 的电话是: {phone_book[name]}")
    else:
        print("未找到该联系人。")

def update_contact():
    name =input("请输入要更新的姓名")
    if name in phone_book:
        print("请输入新的电话号码")
        phone=input();
        phone_book[name]=phone;
    else:
        print("未找到该联系人。")

def delete_contact():
    name=input("请输入你要删除的联系人姓名")
    if name in phone_book:
        del phone_book[name]
        print(f"已将{name}的相关信息删除")
    else:
        print("未找到该联系人。")

def display_all():
    if not phone_book:
        print("字典为空。")
    else:
        print(phone_book)

def main():
    while True:
        print("\n电话簿菜单:")
        print("1. 添加联系人")
        print("2. 查询联系人")
        print("3. 更新联系人")
        print("4. 删除联系人")
        print("5. 遍历字典")
        print("0. 退出")
        choice = input("请输入你的选择: ")
        if choice == '1':
            add_contact()
        elif choice == '2':
            find_contact()
        elif choice=='3':
            update_contact()
        elif choice=='4':
            delete_contact()
        elif choice=='5':
            display_all()
        elif choice == '0':
            break

if __name__ == "__main__":
    main()
\end{lstlisting}

实验结果如图\ref{字典练习结果}
\begin{figure}[htb]
	\centering
	\includegraphics[width=0.48\linewidth]{assets/images/屏幕截图 2025-09-14 183355.png} \hfill
	\includegraphics[width=0.48\linewidth]{assets/images/屏幕截图 2025-09-14 183402.png}
	\caption{字典练习结果}
	\label{字典练习结果}
\end{figure}

\subsection{文件操作}
\begin{questionbox}
    学会使用with open()语句安全地读写文件，并结合字典进行数据统计。这是数据分析和处理的入门。编写一个程序，读取一个.txt文件，统计其中每个单词出现的次数，并将结果按降序输出。
\end{questionbox}
为了解决这个问题，我们可以使用\texttt{with open('article.txt', 'r', encoding='utf-8') as f:}来打开并读取文件内容。\texttt{encoding='utf-8'}确保能正确处理中文字符。\\
读取到的内容是一个长字符串。使用字符串的\texttt{replace()}方法将标点符号（如,, ., ?）替换为空格，并使用\texttt{lower()}方法将所有字母转为小写，以确保"Python"和"python"被计为同一个词。\\
然后使用\texttt{split()}方法将长字符串分割成一个单词列表。\\
然后创建一个空的字典进行词频统计，遍历整个单词列表。\\
最后使用\texttt{sort}函数对字典进行排序,并输出结果。

代码如下：
\begin{lstlisting}
import re

def count_word_frequency(filepath):
    try:
        with open(filepath, 'r', encoding='utf-8') as f:
            text = f.read().lower()
            cleaned_text = re.sub(r'[^\w\s]', '', text)
            words = cleaned_text.split()
            word_count = {}
            for word in words:
                word_count[word] = word_count.get(word, 0) + 1
            sorted_word_count = sorted(word_count.items(), key=lambda item: item[1], reverse=True)
            print("单词词频统计结果:")
            for word, count in sorted_word_count[:10]: 
                print(f"'{word}': {count}")
    except FileNotFoundError:
        print(f"错误: 文件 '{filepath}' 未找到。")

count_word_frequency('test2.txt')
\end{lstlisting}

实验结果如图\ref{python文件操作}
\begin{figure}[htb]
	\centering
	\includegraphics[width=\linewidth]{assets/images/屏幕截图 2025-09-14 190121.png}
	\caption{python文件操作}
	\label{python文件操作}
\end{figure}

\subsection{数据筛选}
\begin{questionbox}
    理解并使用列表推导式（List Comprehension）这一Python标志性特性来简化代码，并掌握列表切片（Slicing）进行数据提取。给定一个数字列表，使用列表推导式生成一个新的列表，其中仅包含原列表中的偶数，并将其平方。然后，使用切片获取新列表的前5个元素。
\end{questionbox}
我们首先创建一个数字列表：numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]\\
使用列表推导式：
\begin{itemize}
    \item 语法为 \texttt{[expression for item in iterable if condition]}。
    \item \texttt{expression} 是 \texttt{x ** 2}，代表对每个元素进行平方。
    \item \texttt{item} 是 \texttt{x}，代表从 \texttt{numbers} 中取出的每个元素。
    \item \texttt{iterable} 是 \texttt{numbers} 列表。
    \item \texttt{condition} 是 \texttt{if x \% 2 == 0}，用于筛选出偶数。
    \item 组合起来就是 \texttt{squared\_evens = [x**2 for x in numbers if x \% 2 == 0]}。
\end{itemize}
代码如下：
\begin{lstlisting}
numbers = list(range(1, 21)) # 生成1到20的数字
squared_evens = [x**2 for x in numbers if x % 2 == 0]
print(f"原始列表中的偶数的平方: {squared_evens}")
top_five = squared_evens[:5]
print(f"新列表的前5个元素: {top_five}")
\end{lstlisting}

结果如图\ref{新列表前5个元素}
\begin{figure}[htb]
	\centering
	\includegraphics[width=\linewidth]{assets/images/屏幕截图 2025-09-14 200812.png}
	\caption{新列表前5个元素}
	\label{新列表前5个元素}
\end{figure}

\subsection{*args, **kwargs 和匿名函数}
\begin{questionbox}
    掌握如何定义能接受任意数量参数的函数，并理解lambda匿名函数的应用场景。编写一个函数calculate\_average(*args)，它可以接收任意数量的数字并返回它们的平均值。使用sorted函数和一个lambda函数，对一个包含元组（tuple）的列表进行排序，排序依据是元组的第二个元素。
\end{questionbox}

代码如下：
\begin{lstlisting}
def calculate_average(*args):
    if not args:
        return 0
    return sum(args) / len(args)

avg = calculate_average(10, 20, 30, 40)
print(f"平均值为: {avg}")

students = [('Alice', 88), ('Bob', 95), ('Charlie', 82)]
sorted_by_score = sorted(students, key=lambda student: student[1], reverse=True)

print(f"\n按分数降序排序后的学生列表: {sorted_by_score}")
\end{lstlisting}

结果如图\ref{降序排列的学生列表}
\begin{figure}[htb]
	\centering
	\includegraphics[width=\linewidth]{assets/images/屏幕截图 2025-09-14 201802.png}
	\caption{降序排列的学生列表}
	\label{降序排列的学生列表}
\end{figure}

\subsection{面向对象}
\begin{questionbox}
     理解类（Class）和对象（Object）的概念，学会定义类的属性（Attributes）和方法（Methods）。创建一个Student类。每个学生对象都应有name（姓名）和grades（一个成绩列表）两个属性。该类还应有一个add\_grade方法用于添加成绩，以及一个get\_average\_ grade方法用于计算平均成绩。
\end{questionbox}

在这里我们使用\texttt{class Student}来定义类。然后构造\texttt{\_init \_:}。然后定义相关的方法（\texttt{add\_grade(self,grade)}和\texttt{get\_average\_ grade(self)}）
\begin{lstlisting}
class Student:
    def __init__(self, name):
        self.name = name
        self.grades = []

    def add_grade(self, grade):
        if isinstance(grade, (int, float)):
            self.grades.append(grade)
        else:
            print("请输入有效的数字成绩。")

    def get_average_grade(self):
        if not self.grades:
            return 0
        return sum(self.grades) / len(self.grades)
    
    def __str__(self): 
        return f"学生姓名: {self.name}, 分数：{self.grades},平均分: {self.get_average_grade():.2f}"

student1 = Student("李华")
student1.add_grade(92)
student1.add_grade(88)
student1.add_grade(95)
print(student1)

student2 = Student("小明")
student2.add_grade(78)
student2.add_grade(82)
print(student2)
\end{lstlisting}

结果如图\ref{类操作}
\begin{figure}[htb]
	\centering
	\includegraphics[width=\linewidth]{assets/images/屏幕截图 2025-09-14 233018.png}
	\caption{类操作}
	\label{类操作}
\end{figure}

\subsection{异常处理}
\begin{questionbox}
    学会使用try...except块来捕获和处理程序运行时可能发生的错误（异常），增强程序的健壮性。编写一个函数，要求用户输入一个整数。程序需要能处理用户输入非数字内容（ValueError）的情况，并持续提示用户重新输入，直到输入正确为止。
\end{questionbox}
为了解决这个问题，我们首先使用\texttt{while true}来创建一个死循环，来不断地输入。\\
然后使用\texttt{try,except}来处理可能引发错误的代码。
\begin{lstlisting}
def get_integer_input(prompt):
    while True:
        try:
            user_input = input(prompt)
            number = int(user_input)
            return number
        except ValueError:
            print("输入无效！请输入一个整数。")

age = get_integer_input("请输入您的年龄: ")
print(f"好的，您的年龄是 {age} 岁。")

quantity = get_integer_input("请输入购买数量: ")
print(f"您购买了 {quantity} 件商品。")
\end{lstlisting}

结果如图\ref{异常处理}
\begin{figure}[htb]
	\centering
	\includegraphics[width=\linewidth]{assets/images/屏幕截图 2025-09-14 235347.png}
	\caption{异常处理}
	\label{异常处理}
\end{figure}

\subsection{datetime模块}
\begin{questionbox}
        了解Python强大的标准库，并学会使用datetime模块处理日期和时间。编写一个程序，计算你出生的那天是星期几，并计算到今天为止你活了多少天。
\end{questionbox}

为了解决这个问题我们首先需要导入模块\texttt{from datetime import datetime}，然后获取当前时间：\texttt{today=datetime.now()}，接着提示用户输入生日年月日。最后计算并输出结果。
代码如下：
\begin{lstlisting}
from datetime import datetime

def life_calculator():
    birth_date_str = input("请输入您的出生日期 (格式 YYYY-MM-DD): ")
    try:
        birth_date = datetime.strptime(birth_date_str, "%Y-%m-%d")
        today = datetime.now()
        weekdays = ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"]
        day_of_week = weekdays[birth_date.weekday()]
        print(f"您出生的那天是: {day_of_week}")
        delta = today - birth_date
        print(f"到今天为止，您已经度过了 {delta.days} 天。")
    except ValueError:
        print("日期格式不正确，请输入类似 '2000-01-30' 的格式。")

life_calculator()
\end{lstlisting}

结果如图\ref{计算生日日期}
\begin{figure}[htb]
	\centering
	\includegraphics[width=\linewidth]{assets/images/屏幕截图 2025-09-15 000137.png}
	\caption{计算生日日期}
	\label{计算生日日期}
\end{figure}

\subsection{request获取API数据}
\begin{questionbox}
    学习如何使用pip安装第三方库，并使用requests库与网络API进行交互，获取真实的网络数据。调用一个公开的API（例如，获取一个随机笑话的API），解析返回的JSON数据，并将其中的关键信息打印出来。
\end{questionbox}

首先我们要做的是安装\texttt{requests},这只需要我们在命令行中输入\texttt{pip install requests}即可。然后导入\texttt{requests}库。这里我们选择的API是\texttt{https://official\-joke\ -api.appspot.com/random\_joke}。接着发送HTTP响应并解析，然后打印数据。
代码如下：
\begin{lstlisting}
import requests

def get_random_joke():
    url = "https://official-joke-api.appspot.com/random_joke"
    try:
        response = requests.get(url)
        response.raise_for_status() 
        joke_data = response.json()
        setup = joke_data['setup']
        punchline = joke_data['punchline']
        print("这是一个随机笑话:")
        print(f"Q: {setup}")
        input("（按回车键查看答案...）")
        print(f"A: {punchline}")

    except requests.exceptions.RequestException as e:
        print(f"获取笑话失败，错误: {e}")

get_random_joke()
\end{lstlisting}

结果如图
\begin{figure}[htb]
	\centering
	\includegraphics[width=\linewidth]{assets/images/屏幕截图 2025-09-15 001042.png}
	\caption{获取API数据}
	\label{获取API数据}
\end{figure}

\subsection{递归-计算阶乘}
\begin{questionbox}
    理解递归（函数调用自身）的基本思想和实现方式，包括基线条件（base case）和递归步骤。编写一个递归函数来计算一个非负整数的阶乘。
\end{questionbox}
这个问题十分的简单，我们只需要定义好递归函数的结束条件和递归过程就好了。代码如下：
\begin{lstlisting}
def factorial(n):
    if n < 0:
        return "阶乘未对负数定义"
    elif n == 0 or n == 1:
        return 1
    else:
        return n * factorial(n - 1)

while True:
    num=int(input("请输入一个整数:"))
    if num==0:
        break
    result=factorial(num)
    print(result)
\end{lstlisting}

结果如图\ref{计算阶乘}
\begin{figure}[htb]
	\centering
	\includegraphics[width=\linewidth]{assets/images/屏幕截图 2025-09-15 002729.png}
	\caption{计算阶乘}
	\label{计算阶乘}
\end{figure}

\subsection{命令行待办事项(To-Do List)应用}
\begin{questionbox}
    将前面学到的所有知识（函数、文件I/O、数据结构、异常处理、用户输入）融会贯通，构建一个完整的小型应用程序。 创建一个命令行的To-Do List应用。功能包括：添加任务、查看所有任务、标记任务为完成、删除任务，并且任务列表能在程序关闭后重新打开时被保留（通过文件存储）。
\end{questionbox}

这是一个综合应用相对比较难。我们第一个要解决的问题是数据存储，使用一个文件（如tasks.txt或tasks.json）来持久化存储任务。我们这里选择JSON格式，它更适合存储结构化数据（如每个任务包含描述和完成状态）。我们核心的数据结构是一个列表，列表中的每一个元素又可以是一个字典。最后需要写一个\texttt{save\_tasks()}函数来把整个列表写入\texttt{tasks.json}文件中。

下面是我们的函数功能：
\begin{enumerate}
    \item \textbf{add\_task()}: 提示用户输入新任务，创建一个新的任务字典，添加到列表中，然后调用 \texttt{save\_tasks()}。
    
    \item \textbf{view\_tasks()}: 遍历任务列表，并以清晰的格式打印出来，包括任务编号和完成状态。
    
    \item \textbf{complete\_task()}: 提示用户输入要标记为完成的任务编号，将对应任务的 'completed' 值改为 True，然后保存。
    
    \item \textbf{delete\_task()}: 提示用户输入要删除的任务编号，从列表中移除该任务，然后保存。
\end{enumerate}
代码如下;
\begin{lstlisting}
import json
import os
import time

TASKS_FILE = "tasks.json"

def load_tasks():
    if os.path.exists(TASKS_FILE):
        with open(TASKS_FILE, 'r', encoding='utf-8') as f:
            try:
                return json.load(f)
            except json.JSONDecodeError:
                return []
    return []

def save_tasks(tasks):
    with open(TASKS_FILE, 'w', encoding='utf-8') as f:
        json.dump(tasks, f, indent=4, ensure_ascii=False)

def view_tasks(tasks):
    print("\n--- 你的待办事项 ---")
    if not tasks:
        print("太棒了！当前没有待办任务。")
    else:
        for i, task in enumerate(tasks, 1):
            status_symbol = "✓" if task['completed'] else " "
            print(f"{i}. [{status_symbol}] {task['task']}")
    print("--------------------")

def add_task(tasks):
    task_description = input("请输入新的任务内容: ")
    if task_description.strip():
        new_task = {'task': task_description, 'completed': False}
        tasks.append(new_task)
        save_tasks(tasks)
        print(f"✅ 任务 '{task_description}' 已添加。")
    else:
        print("❌ 错误：任务内容不能为空。")

def complete_task(tasks):
    view_tasks(tasks)
    if not tasks:
        return # 如果没有任务，直接返回
    try:
        task_num_str = input("请输入要标记为【完成】的任务编号: ")
        task_num = int(task_num_str)
        if 1 <= task_num <= len(tasks):
            task_index = task_num - 1
            if not tasks[task_index]['completed']:
                tasks[task_index]['completed'] = True
                save_tasks(tasks)
                print(f"🎉 任务 '{tasks[task_index]['task']}' 已标记为完成。")
            else:
                print(f"🤔 任务 '{tasks[task_index]['task']}' 已经是完成状态了。")
        else:
            print(f"❌ 错误：无效的编号。请输入 1 到 {len(tasks)} 之间的数字。")
    except ValueError:
        print("❌ 错误：请输入一个有效的数字编号。")

def delete_task(tasks):
    view_tasks(tasks)
    if not tasks:
        return # 如果没有任务，直接返回    
    try:
        task_num_str = input("请输入要【删除】的任务编号: ")
        task_num = int(task_num_str)

        if 1 <= task_num <= len(tasks):
            task_index = task_num - 1
            removed_task = tasks.pop(task_index)
            save_tasks(tasks)
            print(f"🗑️ 任务 '{removed_task['task']}' 已被删除。")
        else:
            print(f"❌ 错误：无效的编号。请输入 1 到 {len(tasks)} 之间的数字。")
    except ValueError:
        print("❌ 错误：请输入一个有效的数字编号。")

def main():
    tasks = load_tasks()    
    while True:
        # 打印主菜单
        print("\n===== 命令行 To-Do List 应用 =====")
        print("1. 查看所有任务")
        print("2. 添加新任务")
        print("3. 标记任务为完成")
        print("4. 删除任务")
        print("5. 退出程序")
        print("==================================")        
        choice = input("请选择一个操作 (1-5): ")        
        if choice == '1':
            view_tasks(tasks)
        elif choice == '2':
            add_task(tasks)
        elif choice == '3':
            complete_task(tasks)
        elif choice == '4':
            delete_task(tasks)
        elif choice == '5':
            print("感谢使用，再见！👋")
            time.sleep(1) # 暂停1秒，让用户看到消息
            break # 退出 while 循环，结束程序
        else:
            print("❌ 无效的输入，请输入 1 到 5 之间的数字。")
        input("\n按 Enter 键继续...")

if __name__ == "__main__":
    main()
\end{lstlisting}

结果如图\ref{命令行待办事项}
\begin{figure}[H]
	\centering
	\includegraphics[width=0.4\linewidth]{assets/images/屏幕截图 2025-09-15 004036.png} \hfill
	\includegraphics[width=0.35\linewidth]{assets/images/image.png}
	\caption{命令行待办事项}
	\label{命令行待办事项}
\end{figure}